#pragma once
#include<iostream>
#include<assert.h>

namespace Test
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		string(const char* str="\0")
			:_size(std::strlen(str))
		{
			_capacity = _size;
		    _str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		string(const string&s)
		{
			_str = new char[s._size+1];
			_size = s._size; 
			_capacity = _size;
			while (_capacity < s._size)
			{
				reserve(_capacity*2);
			}
			strcpy(_str, s._str);
		}

		void reserve(size_t capacity)
		{
			if (capacity == 0)capacity = 2;
			_capacity = capacity;
			char* tmp = new char[capacity + 1];
			strcpy(tmp, _str);
			if(_str!=nullptr)delete[] _str;
			_str = tmp;
		}

		void push_back(const char ch)
		{
			if (_size + 1 > _capacity)
			{
				reserve(_capacity * 2);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}

		void append(const char* str)
		{
			size_t len = std::strlen(str);
			while (_size + len > _capacity)
			{
				reserve(_capacity * 2);
			}
			while (*str != '\0')
			{
				_str[_size] = *str;
				_size++;
				str++; 
			}
			_str[_size] = '\0';
		}

		void insert(const char ch)
		{
			if (_size + 1 > _capacity)
			{
				reserve(_capacity * 2);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}

		void insert(const char* str)
		{
			size_t len = std::strlen(str);
			while (_size + len > _capacity)
			{
				reserve(_capacity * 2);
			}
			while (*str != '\0')
			{
				_str[_size] = *str;
				_size++;
				str++;
			}
			_str[_size] = '\0';
		}

		void insert(const size_t pos, const char ch)
		{
			assert(pos < _size&&pos>=0);
			if (_size + 1 > _capacity)reserve(_capacity * 2);
			size_t n =_size+1;
			while (n >pos)
			{
				_str[n] = _str[n-1];
				--n;
			}
			_str[pos] = ch;
			_size++;
			_str[_size] = '\0';
		}

		void insert(const size_t pos, const char* str)
		{
			assert(pos < _size && pos >= 0);
			size_t len = std::strlen(str);
			while (_size + len > _capacity)
			{
				reserve(_capacity);
			}
			size_t n = _size + len+1;
			while (n >= pos+ len-1 )
			{
				_str[n] = _str[n - len];
				--n;
			}
			_size += len;
			//_str[_size] = '\0';
			std::strncpy(_str + pos,str,len);
		}

		void erase(size_t pos, size_t n=npos)
		{
			assert(pos < _size && pos >= 0);
			size_t m = pos;
			if (n == npos||pos+n>_size)
			{
				_str[m] = '\0';
				return;
			}
			while (1)
			{
				if (_str[m+n-1] == '\0')return;
				_str[m] = _str[m + n];
				m++;
			}
			_str[m] = '\0';
		}

		const char* c_str()
		{
			return _str;
		}

		const size_t strlen()
		{
			return _size;
		}

		string& operator+=(const char ch)
		{
			push_back(ch);
			return *this;
		}

		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}

		char& operator[](const size_t pos)
		{
			return _str[pos];
		}

		/*string& operator()(const string& s)
		{
			size_t n = s._size;
			while (_capacity < n)
			{
				reserve(_capacity * 2);
			}
			strcpy(_str, s._str);
		}*/

		~string()
		{
			delete[] _str;
			_size = 0;
			_capacity = 0;
		}

	private:
		char* _str;
		size_t _size;
		size_t _capacity;

		static size_t npos;
	};

	size_t string::npos = -1;

	void test_string_1()
	{
		string s1;
		string s2("Hello world!");
		std::cout << s1.c_str() << std::endl;
		std::cout << s2.c_str() << std::endl;
	}

	void test_string_2()
	{
		string s1("Hello world!");
		size_t i = 0;
		while (s1[i] != '\0')
		{
			std::cout << s1[i]<<" ";
			++i;
		}
		s1[0]++;
		i = 0;
		std::cout << std::endl;
		while (s1[i] != '\0')
		{
			std::cout << s1[i] << " ";
			++i;
		}
	}

	void test_string_3()
	{
		string s("Hello world!");
		s.push_back('*');
		s.push_back('#');
		std::cout << s.c_str() << std::endl;
		s.append("###");
		std::cout << s.c_str() << std::endl;
		s.append("***");
		std::cout << s.c_str() << std::endl;
	}

	void test_string_4()
	{
		string s1("Hello world!");
		s1 += '*';
		s1 += '#';
		std::cout << s1.c_str() << std::endl;
		s1 += " hello world";
		s1 += "###";
		std::cout << s1.c_str() << std::endl;
			
	}

	void test_string_5()
	{
		string s("Hello world!");
		string::iterator begin = s.begin();
		while (*begin != '\0')
		{
			std::cout <<*begin << ' ' ;
			begin++;
		}
		std::cout << std::endl;
		for (auto au : s)
		{
			std::cout << au << ' ' ;
		}
	}

	void test_string_6()
	{
		string s("Hello world!");
		s.insert('*');
		std::cout << s.c_str() << std::endl;
		s.insert(" Hello world!");
		std::cout << s.c_str() << std::endl;
	}

	void test_string_7()
	{
		string s("Hello world!");
		s.insert(0, '*');
	    std::cout << s.c_str() << std::endl;
		s.insert(s.strlen()-1, '*');
		std::cout << s.c_str() << std::endl;
		s.insert(6, "##");
		std::cout << s.c_str() << std::endl;
		s.insert(0, "##");
		std::cout << s.c_str() << std::endl;
	}

	void test_string_8()
	{
		string s1("Hello world!");
		/*string s2;
		std::cout << s2.c_str() << std::endl;*/
		string s2(s1);
		string s3(s1);
		s1.erase(5);
		std::cout << s1.c_str() << std::endl;
		s2.erase(5, 11);
		std::cout << s2.c_str() << std::endl;
		s3.erase(5, 1);
		std::cout << s3.c_str() << std::endl;
	}
}